This fixes the following scenerio:
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Wed, 16 Nov 2005 10:41:14 +0000 (11:41 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Wed, 16 Nov 2005 10:41:14 +0000 (11:41 +0100)
1) gmfn X is L2 table, and a shadow for it is set.
2) A write to page X, and the same page would be L1 table
also.(Something like the linear page table) But the shadow for L1 table
is not set.

The code path will be shadow_fault -> l1pte_write_fault. Because X is L2
table, so shadow_mark_va_out_of_sync is called , this function will
allocate a OO entry for this table, and set the writable_pl1e to -1.
Also it alloc a L1 shadow for X through shadow_map_l1_into_current_l2.
When allocating, free_out_of_sync_state will be called to free all OO
entry. However, since the OO entry allocated on
shadow_mark_va_out_of_sync has the writable_pl1e to -1, this OO entry
will never be released.

Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
xen/arch/x86/shadow.c
xen/arch/x86/shadow32.c

index 19eef963c6daf262ea1dd125188505d0e3d82f6d..e336878b9ef40db1d9b556957fe37f821b1c1fda 100644 (file)
@@ -873,7 +873,7 @@ shadow_make_snapshot(
 }
 
 static struct out_of_sync_entry *
-mark_mfn_out_of_sync(struct vcpu *v, unsigned long gpfn,
+__mark_mfn_out_of_sync(struct vcpu *v, unsigned long gpfn,
                              unsigned long mfn)
 {
     struct domain *d = v->domain;
@@ -909,7 +909,6 @@ mark_mfn_out_of_sync(struct vcpu *v, unsigned long gpfn,
     entry->v = v;
     entry->gpfn = gpfn;
     entry->gmfn = mfn;
-    entry->snapshot_mfn = shadow_make_snapshot(d, gpfn, mfn);
     entry->writable_pl1e = -1;
 
 #if 0 // this code has not been updated for 32pae & 64 bit modes
@@ -923,20 +922,34 @@ mark_mfn_out_of_sync(struct vcpu *v, unsigned long gpfn,
     //
     get_page(page, d);
 
+    return entry;
+}
+
+static struct out_of_sync_entry *
+mark_mfn_out_of_sync(struct vcpu *v, unsigned long gpfn,
+                             unsigned long mfn)
+{
+    struct out_of_sync_entry *entry =
+        __mark_mfn_out_of_sync(v, gpfn, mfn);
+    struct domain *d = v->domain;
+
+    entry->snapshot_mfn = shadow_make_snapshot(d, gpfn, mfn);
     // Add to the out-of-sync list
     //
     entry->next = d->arch.out_of_sync;
     d->arch.out_of_sync = entry;
 
     return entry;
+
 }
 
 static void shadow_mark_va_out_of_sync(
     struct vcpu *v, unsigned long gpfn, unsigned long mfn, unsigned long va)
 {
     struct out_of_sync_entry *entry =
-        shadow_mark_mfn_out_of_sync(v, gpfn, mfn);
+        __mark_mfn_out_of_sync(v, gpfn, mfn);
     l2_pgentry_t sl2e;
+    struct domain *d = v->domain;
 
 #if CONFIG_PAGING_LEVELS >= 4
     {
@@ -971,6 +984,7 @@ static void shadow_mark_va_out_of_sync(
     }
     ASSERT(l2e_get_flags(sl2e) & _PAGE_PRESENT);
 
+    entry->snapshot_mfn = shadow_make_snapshot(d, gpfn, mfn);
     // NB: this is stored as a machine address.
     entry->writable_pl1e =
         l2e_get_paddr(sl2e) | (sizeof(l1_pgentry_t) * l1_table_offset(va));
@@ -983,6 +997,11 @@ static void shadow_mark_va_out_of_sync(
     if ( !get_shadow_ref(l2e_get_pfn(sl2e)) )
         BUG();
 
+    // Add to the out-of-sync list
+    //
+    entry->next = d->arch.out_of_sync;
+    d->arch.out_of_sync = entry;
+
     FSH_LOG("mark_out_of_sync(va=%lx -> writable_pl1e=%lx)",
             va, entry->writable_pl1e);
 }
index 629ebe16be53e1496d1ce03578f55c57bff36761..e3a53898439e2607432726d46832be748cdcfb6e 100644 (file)
@@ -1826,7 +1826,7 @@ shadow_free_snapshot(struct domain *d, struct out_of_sync_entry *entry)
 }
 
 struct out_of_sync_entry *
-shadow_mark_mfn_out_of_sync(struct vcpu *v, unsigned long gpfn,
+__shadow_mark_mfn_out_of_sync(struct vcpu *v, unsigned long gpfn,
                              unsigned long mfn)
 {
     struct domain *d = v->domain;
@@ -1862,7 +1862,6 @@ shadow_mark_mfn_out_of_sync(struct vcpu *v, unsigned long gpfn,
     entry->v = v;
     entry->gpfn = gpfn;
     entry->gmfn = mfn;
-    entry->snapshot_mfn = shadow_make_snapshot(d, gpfn, mfn);
     entry->writable_pl1e = -1;
 
 #if SHADOW_DEBUG
@@ -1874,6 +1873,18 @@ shadow_mark_mfn_out_of_sync(struct vcpu *v, unsigned long gpfn,
     //
     get_page(page, d);
 
+    return entry;
+}
+
+struct out_of_sync_entry *
+shadow_mark_mfn_out_of_sync(struct vcpu *v, unsigned long gpfn,
+                             unsigned long mfn)
+{
+    struct out_of_sync_entry *entry =
+      __shadow_mark_mfn_out_of_sync(v, gpfn, mfn);
+    struct domain *d = v->domain;
+
+    entry->snapshot_mfn = shadow_make_snapshot(d, gpfn, mfn);
     // Add to the out-of-sync list
     //
     entry->next = d->arch.out_of_sync;
@@ -1886,8 +1897,9 @@ void shadow_mark_va_out_of_sync(
     struct vcpu *v, unsigned long gpfn, unsigned long mfn, unsigned long va)
 {
     struct out_of_sync_entry *entry =
-        shadow_mark_mfn_out_of_sync(v, gpfn, mfn);
+        __shadow_mark_mfn_out_of_sync(v, gpfn, mfn);
     l2_pgentry_t sl2e;
+    struct domain *d = v->domain;
 
     // We need the address of shadow PTE that maps @va.
     // It might not exist yet.  Make sure it's there.
@@ -1902,6 +1914,7 @@ void shadow_mark_va_out_of_sync(
     }
     ASSERT(l2e_get_flags(sl2e) & _PAGE_PRESENT);
 
+    entry->snapshot_mfn = shadow_make_snapshot(d, gpfn, mfn);
     // NB: this is stored as a machine address.
     entry->writable_pl1e =
         l2e_get_paddr(sl2e) | (sizeof(l1_pgentry_t) * l1_table_offset(va));
@@ -1914,6 +1927,11 @@ void shadow_mark_va_out_of_sync(
     if ( !get_shadow_ref(l2e_get_pfn(sl2e)) )
         BUG();
 
+    // Add to the out-of-sync list
+    //
+    entry->next = d->arch.out_of_sync;
+    d->arch.out_of_sync = entry;
+
     FSH_LOG("mark_out_of_sync(va=%lx -> writable_pl1e=%lx)",
             va, entry->writable_pl1e);
 }